<?php
#
# dmBridge: a data access framework for CONTENTdm(R)
#
# Copyright © 2009, 2010, 2011 Board of Regents of the Nevada System of Higher
# Education, on behalf of the University of Nevada, Las Vegas
#

/**
 * @author Alex Dolski <alex.dolski@unlv.edu>
 * @license http://www.opensource.org/licenses/mit-license.php
 */
class DMXMLRepresentationTransformerV1 extends DMXMLRepresentationTransformer
implements DMHTTPAPIRepresentationTransformer {

	/**
	 * @var int
	 */
	protected $version = 1;


	/**
	 * @return XML-encoded string
	 */
	public function nullResponse() {
		$this->dxml->documentElement->appendChild(
			$this->dxml->createElement("querySeconds", $this->getQSeconds()));
		return $this->output();
	}

	/**
	 * @param DMCollection col
	 * @return XML-encoded string
	 * @since 0.3
	 */
	public function transformCollection(DMCollection $col) {
		$this->addSchema("collection_view");
		$colnode = $this->dxml->createElement("dmCollection");
		$this->dxml->documentElement->appendChild($colnode);
		// alias
		$colnode->setAttribute("alias", $col->getAlias());
		// title
		$colnode->appendChild(
			$this->dxml->createElement("name",
				DMString::xmlentities($col->getName()))
		);
		// # of objects
		$colnode->appendChild(
			$this->dxml->createElement("numObjects",
				DMString::xmlentities($col->getNumObjects())));
		$this->dxml->documentElement->appendChild($colnode);
		// overview page
		if ($col->getOverviewURI()) {
			$overview = $this->dxml->createElement("overview");
			$overview->setAttribute("xlink:href", $col->getOverviewURI());
			$colnode->appendChild($overview);
		}
		// description
		if ($col->getDescription()) {
			$desc = $this->dxml->createElement("description",
					$col->getDescription());
			$colnode->appendChild($desc);
		}
		// image
		if ($col->getImage512URI()) {
			$img = $this->dxml->createElement("image512");
			$img->setAttribute("xlink:href", $col->getImage512URI());
			$colnode->appendChild($img);
		}
		// fields
		$fields = $this->dxml->createElement("fields");
		foreach ($col->getFields() as $f) {
			if ($f->isHidden()) {
				continue;
			}
			$field = $this->dxml->createElement("dmField");
			$field->setAttribute("nick", $f->getNick());
			$field->setAttribute("name", $f->getName());
			$field->setAttribute("isControlled", (int) $f->isControlled());
			$field->setAttribute("isSearchable", (int) $f->isSearchable());
			$field->setAttribute("dc", $f->getDCNick());
			$field->setAttribute("type", $f->getType());
			$fields->appendChild($field);
		}
		$colnode->appendChild($fields);
		return $this->output();
	}

	/**
	 * @param array collections Indexed array of DMCollection objects
	 * @return XML-encoded string
	 * @since 0.4
	 */
	public function transformCollections(array $collections) {
		$this->addSchema('collections_list');
		foreach ($collections as $c) {
			if (!$c instanceof DMCollection) {
				continue;
			}
			$colnode = $this->dxml->createElement('dmCollection');
			// alias
			$colnode->setAttribute('alias', $c->getAlias());

			// URI
			$colnode->setAttribute('xlink:type', 'simple');
			$colnode->setAttribute('xlink:href',
					$c->getURI(DMBridgeComponent::HTTPAPI));

			// title
			$colnode->appendChild(
				$this->dxml->createElement('name',
					DMString::xmlentities($c->getName())));
			// # of objects
			$colnode->appendChild(
				$this->dxml->createElement('numObjects',
					DMString::xmlentities($c->getNumObjects())));
			$this->dxml->documentElement->appendChild($colnode);
		}
		return $this->output();
	}

	/**
	 * @param DMComment comment
	 * @return XML-encoded string
	 * @since 0.3
	 */
	public function transformComment(DMComment $comment) {
		$this->addSchema('comment_view');
		// object
		$object = $this->dxml->createElement('dmObject');
		$object->setAttribute('alias',
				$comment->getObject()->getCollection()->getAlias());
		$object->setAttribute('pointer', $comment->getObject()->getPtr());
		$object->setAttribute('xlink:type', 'simple');
		$object->setAttribute('xlink:href',
				$comment->getObject()->getURI(DMBridgeComponent::HTTPAPI));

		// comment
		$cnode = $this->dxml->createElement('dmComment');
		// id
		$cnode->setAttribute('id', $comment->getID());
		// timestamp
		$cnode->setAttribute('timestamp', $comment->getTimestamp()->asISO8601());

		// poster
		$poster = $this->dxml->createElement('poster');
		$poster->appendChild(
			$this->dxml->createElement('name',
					DMString::xmlentities($comment->getName())));
		$poster->appendChild(
			$this->dxml->createElement('email',
					DMString::xmlentities($comment->getEmail())));
		$cnode->appendChild($poster);
		// text
		$cnode->appendChild(
			$this->dxml->createElement('body',
					DMString::xmlentities($comment->getValue())));
		$object->appendChild($cnode);
		$this->dxml->documentElement->appendChild($object);
		return $this->output();
	}

	/**
	 * @param array comments
	 * @param int page
	 * @param int rpp Comments per page
	 * @param int total
	 * @return XML-encoded string
	 * @since 0.3
	 */
	public function transformComments(array $comments, $page, $rpp, $total) {
		$this->addSchema('comments_list');
		$node = $this->dxml->createElement('comments');
		$node->setAttribute('page', $page);
		$node->setAttribute('perPage', $rpp);
		$node->setAttribute('numPages', ceil($total / $rpp));
		$node->setAttribute('total', $total);
		foreach ($comments as $c) {
			$cnode = $this->dxml->createElement('dmComment');
			$cnode->setAttribute('id', $c->getID());
			$cnode->setAttribute('xlink:type', 'simple');
			$cnode->setAttribute('xlink:href',
					$c->getURI(DMBridgeComponent::HTTPAPI));
			$node->appendChild($cnode);
		}
		$this->dxml->documentElement->appendChild($node);
		return $this->output();
	}

	/**
	 * @param Exception ex
	 * @return XML-encoded string
	 * @since 0.4
	 */
	public function transformException(Exception $ex) {
		self::__construct(); // clear any xml that has been generated up til now
		$this->addSchema('exception');
		$node = $this->dxml->createElement('dmException');
		// message
		$node->appendChild(
			$this->dxml->createElement('message',
				DMString::xmlentities($ex->getMessage())));
		if (DMConfigIni::getInstance()->getString("dmbridge.debug_mode")) {
			$node->setAttribute('type', get_class($ex));
			// stack trace
			$node->appendChild(
				$this->dxml->createElement('stackTrace',
					DMString::xmlentities($ex->getTraceAsString())));
		}
		$doc = $this->dxml->createElement('documentation');
		$doc->setAttribute('xlink:type', 'simple');
		$doc->setAttribute('xlink:href',
			DMInternalURI::getURIWithParams("api/1/doc", array(), "html"));
		$node->appendChild($doc);

		$this->dxml->documentElement->appendChild($node);
		return $this->output();
	}

	/**
	 * @param DMObject obj
	 * @return XML-encoded string
	 * @since 0.3
	 */
	public function transformObject(DMObject $obj) {
		$this->addSchema('object_view');
		$objnode = $this->dxml->createElement('dmObject');
		// alias
		$objnode->setAttribute('alias', $obj->getCollection()->getAlias());
		// pointer
		$objnode->setAttribute('pointer', $obj->getPtr());
		// created
		$objnode->setAttribute('created', $obj->getDateCreated()->asISO8601());
		// last updated
		$objnode->setAttribute('lastUpdated', $obj->getDateUpdated()->asISO8601());
		// is compound
		$objnode->setAttribute('isCompound', (int) $obj->isCompound());

		// compound object page & title
		if ($obj->getParent()) {
			$objnode->setAttribute('page', $obj->getPage());
			$objnode->setAttribute('title', $obj->getTitle());
		}

		// web template
		$node = $this->dxml->createElement('webTemplate');
		$node->setAttribute('xlink:type', 'simple');
		$node->setAttribute('xlink:href', $obj->getReferenceURL());
		$objnode->appendChild($node);

		// file
		$node = $this->dxml->createElement('file');
		$node->setAttribute('xlink:type', 'simple');
		$node->setAttribute('xlink:href', $obj->getFileURL());
		$node->appendChild(
			$this->dxml->createElement('filename',
				DMString::xmlentities($obj->getFilename())));
		$node->appendChild(
			$this->dxml->createElement("mimeType",
				DMString::xmlentities($obj->getMediaType())));
		$node->appendChild(
			$this->dxml->createElement('height', (int) $obj->getHeight()));
		$node->appendChild(
			$this->dxml->createElement('width', (int) $obj->getWidth()));
		$objnode->appendChild($node);

		// image
		$node = $this->dxml->createElement('image');
		$node->setAttribute('generator',
				rtrim(DMHTTPRequest::getCurrent()->getURI()->getAbsoluteHostURI(), "/")
					. DMConfigIni::getInstance()->getString(
							"contentdm.getimage_exe.path"));
		$sm = $this->dxml->createElement('small');
		$med = $this->dxml->createElement('medium');
		$lg = $this->dxml->createElement('large');
		$sm->setAttribute('xlink:type', 'simple');
		$med->setAttribute('xlink:type', 'simple');
		$lg->setAttribute('xlink:type', 'simple');
		$sm->setAttribute('xlink:href', $obj->getImageURL(300, 300));
		$med->setAttribute('xlink:href', $obj->getImageURL(600, 600));
		$lg->setAttribute('xlink:href', $obj->getImageURL(900, 900));
		$node->appendChild($sm);
		$node->appendChild($med);
		$node->appendChild($lg);
		$objnode->appendChild($node);

		// thumbnail
		$node = $this->dxml->createElement('thumbnail');
		$node->setAttribute('xlink:type', 'simple');
		$node->setAttribute('xlink:href', $obj->getThumbnailURL());
		$objnode->appendChild($node);

		// rating
		$ds = DMDataStoreFactory::getDataStore();
		$rating = $this->dxml->createElement('rating');
		$rating->setAttribute('numRatings',
				(int) $ds->getNumRatingsForObject($obj));
		$rating->setAttribute('average',
				DMString::xmlentities($obj->getRating(100)));
		$objnode->appendChild($rating);

		// parent
		$parent = $this->dxml->createElement('parent');
		if ($obj->getParent()) {
			$parent->setAttribute('alias',
					$obj->getParent()->getCollection()->getAlias());
			$parent->setAttribute('pointer', $obj->getParent()->getPtr());
			$parent->setAttribute('xlink:type', 'simple');
			$parent->setAttribute('xlink:href',
					$obj->getParent()->getURI(DMBridgeComponent::HTTPAPI));
		}
		$objnode->appendChild($parent);

		// children
		$children = $this->dxml->createElement('children');
		foreach ($obj->getChildren() as $c) {
			$child = $this->dxml->createElement('dmObject');
			$child->setAttribute('pointer', $c->getPtr());
			$child->setAttribute('xlink:type', 'simple');
			$child->setAttribute('xlink:href',
					$c->getURI(DMBridgeComponent::HTTPAPI));
			$title = $this->dxml->createElement('title',
				DMString::xmlentities($c->getTitle()));
			$thumb = $this->dxml->createElement('thumbnail');
			$thumb->setAttribute('xlink:href', $c->getThumbnailURL());
			$child->appendChild($title);
			$child->appendChild($thumb);
			$children->appendChild($child);
		}
		$objnode->appendChild($children);

		// metadata
		$metadata = $this->dxml->createElement('metadata');
		foreach ($obj->getMetadata() as $f) {
			if (strlen($f->getValue()) < 1 || $f->isHidden()) {
				continue;
			}
			$node = $metadata->appendChild(
				$this->dxml->createElement(
					'field', DMString::xmlentities($f->getValue())));
			$node->setAttribute('nick', DMString::xmlentities($f->getNick()));
			$node->setAttribute('name', DMString::xmlentities($f->getName()));
			$node->setAttribute('dc', DMString::xmlentities($f->getDCNick()));
			$node->setAttribute('controlled', $f->isControlled() ? 1 : 0);
			$node->setAttribute('searchable', $f->isSearchable() ? 1 : 0);
		}
		$objnode->appendChild($metadata);

		// tags
		$tq = new DMTagQuery($ds);
		$tq->addObject($obj);
		$tq->setApproved(1);
		$tags = $this->dxml->createElement('tags');
		foreach ($tq->getSearchResultsAsObjects() as $t) {
			$tag = $this->dxml->createElement('dmTag',
				DMString::xmlentities($t->getValue()));
			$tag->setAttribute('id', $t->getID());
			$tag->setAttribute('xlink:type', 'simple');
			$tag->setAttribute('xlink:href',
					$t->getURI(DMBridgeComponent::HTTPAPI));
			$tags->appendChild($tag);
		}
		$objnode->appendChild($tags);

		// comments
		$comments = $this->dxml->createElement('comments');
		foreach (DMDataStoreFactory::getDataStore()
				->getApprovedCommentsForObject($obj, 1, 1000) as $c) {
			$comment = $this->dxml->createElement('dmComment');
			$comment->setAttribute('id', $c->getID());
			$comment->setAttribute('xlink:type', 'simple');
			$comment->setAttribute('xlink:href',
					$c->getURI(DMBridgeComponent::HTTPAPI));
			$comments->appendChild($comment);
		}
		$objnode->appendChild($comments);

		$this->dxml->documentElement->appendChild($objnode);
		return $this->output();
	}

	/**
	 * @param DMObject obj
	 * @param int page
	 * @param int rpp Results per page
	 * @return XML-encoded string
	 * @since 0.3
	 */
	public function transformObjectComments(DMObject $obj, $page, $rpp) {
		$this->addSchema('object_comments');
		$comments = DMDataStoreFactory::getDataStore()
			->getApprovedCommentsForObject($obj, $page, $rpp);
		$onode = $this->dxml->createElement('dmObject');
		$onode->setAttribute('alias', $obj->getCollection()->getAlias());
		$onode->setAttribute('pointer', $obj->getPtr());
		$onode->setAttribute('xlink:type', 'simple');
		$onode->setAttribute('xlink:href',
				$obj->getURI(DMBridgeComponent::HTTPAPI));
		foreach ($comments as $c) {
			if (!$c instanceof DMComment) {
				continue;
			}
			$cnode = $this->dxml->createElement('dmComment');
			// id
			$cnode->setAttribute('id', $c->getID());
			$cnode->setAttribute('xlink:type', 'simple');
			$cnode->setAttribute('xlink:href',
					$c->getURI(DMBridgeComponent::HTTPAPI));
			// timestamp
			$cnode->setAttribute('timestamp', $c->getTimestamp()->asISO8601());
			// poster
			$poster = $this->dxml->createElement('poster');
			$poster->appendChild(
				$this->dxml->createElement('name',
					DMString::xmlentities($c->getName())));
			$poster->appendChild(
				$this->dxml->createElement('email',
					DMString::xmlentities($c->getEmail())));
			$cnode->appendChild($poster);
			// text
			$cnode->appendChild(
				$this->dxml->createElement(
					'body', DMString::xmlentities($c->getValue())));
			$onode->appendChild($cnode);

		}
		$this->dxml->documentElement->appendChild($onode);
		return $this->output();
	}

	/**
	 * @param DMObject obj
	 * @return XML-encoded string
	 * @since 0.4
	 */
	public function transformObjectRating(DMObject $obj) {
		$this->addSchema('object_rating');
		$ds = DMDataStoreFactory::getDataStore();

		$onode = $this->dxml->createElement('dmObject');
		$onode->setAttribute('alias', $obj->getCollection()->getAlias());
		$onode->setAttribute('pointer', $obj->getPtr());
		$onode->setAttribute('xlink:type', 'simple');
		$onode->setAttribute('xlink:href',
				$obj->getURI(DMBridgeComponent::HTTPAPI));

		$rnode = $this->dxml->createElement('rating');
		$rnode->setAttribute('numRatings', $ds->getNumRatingsForObject($obj));
		$rnode->setAttribute('average', $obj->getRating());
		$onode->appendChild($rnode);
		$this->dxml->documentElement->appendChild($onode);
		return $this->output();
	}

	/**
	 * @param DMObject obj
	 * @return XML-encoded string
	 * @since 0.4
	 */
	public function transformObjectTags(DMObject $obj) {
		$this->addSchema('object_tags');

		$onode = $this->dxml->createElement('dmObject');
		$onode->setAttribute('alias', $obj->getCollection()->getAlias());
		$onode->setAttribute('pointer', $obj->getPtr());
		$onode->setAttribute('xlink:type', 'simple');
		$onode->setAttribute('xlink:href',
				$obj->getURI(DMBridgeComponent::HTTPAPI));

		$ds = DMDataStoreFactory::getDataStore();
		$tq = new DMTagQuery($ds);
		$tq->addObject($obj);
		$tq->setApproved(1);
		$tags = $this->dxml->createElement('tags');
		foreach ($tq->getSearchResultsAsObjects() as $t) {
			$tag = $this->dxml->createElement('dmTag',
				DMString::xmlentities($t->getValue()));
			$tag->setAttribute('xlink:type', 'simple');
			$tag->setAttribute('xlink:href',
					$t->getURI(DMBridgeComponent::HTTPAPI));
			$tags->appendChild($tag);
		}
		$onode->appendChild($tags);

		$this->dxml->documentElement->appendChild($onode);
		return $this->output();
	}

	/**
	 * @param DMObjectQuery q
	 * @return XML-encoded string
	 * @since 1.0
	 */
	public function transformRatings(DMObjectQuery $q) {
		$this->addSchema('objects_list_ratings');

		// results
		$results = $this->dxml->createElement('results');
		$results->setAttribute('perPage', $q->getNumResultsPerPage());
		$results->setAttribute('total', $q->getNumResults());

		foreach ($q->getSearchResults() as $obj) {
			$objnode = $this->dxml->createElement('dmObject');
			$objnode->setAttribute('alias', $obj->getCollection()->getAlias());
			$objnode->setAttribute('pointer', $obj->getPtr());
			$objnode->setAttribute('xlink:type', 'simple');
			$objnode->setAttribute('xlink:href',
					$obj->getURI(DMBridgeComponent::HTTPAPI));
			$objnode->appendChild(
					$this->dxml->createElement("rating", $obj->getRating()));
			$results->appendChild($objnode);
		}
		$this->dxml->documentElement->appendChild($results);

		return $this->output();
	}

	/**
	 * @param DMObjectQuery q
	 * @return XML-encoded string
	 * @since 0.3
	 */
	public function transformResults(DMObjectQuery $q) {
		$this->addSchema('objects_list');
		// suggestion
		if ($q->getSuggestion()) {
			$sugnode = $this->dxml->createElement('suggestion',
					$q->getSuggestion());
			$this->dxml->documentElement->appendChild($sugnode);
		}

		// results
		$results = $this->dxml->createElement('results');
		$results->setAttribute('page', $q->getPage());
		$results->setAttribute('perPage', $q->getNumResultsPerPage());
		$results->setAttribute('numPages', $q->getNumPages());
		$results->setAttribute('total', $q->getNumResults());

		foreach ($q->getSearchResults() as $obj) {
			$objnode = $this->dxml->createElement('dmObject');
			$objnode->setAttribute('alias', $obj->getCollection()->getAlias());
			$objnode->setAttribute('pointer', $obj->getPtr());
			$objnode->setAttribute('xlink:type', 'simple');
			$objnode->setAttribute('xlink:href',
					$obj->getURI(DMBridgeComponent::HTTPAPI));
			$results->appendChild($objnode);
		}
		$this->dxml->documentElement->appendChild($results);

		// facets
		$facets = $this->dxml->createElement('facets');
		foreach ($q->getFacetTerms() as $f) {
			$fnode = $this->dxml->createElement('dmFacetTerm',
				DMString::xmlentities($f->getField()->getValue()));
			$fnode->setAttribute('field', $f->getField()->getNick());
			$fnode->setAttribute('name', $f->getField()->getName());
			$fnode->setAttribute('count', $f->getCount());
			$fnode->setAttribute('xlink:type', 'simple');
			$fnode->setAttribute('xlink:href',
					$f->getURI(DMBridgeComponent::HTTPAPI));
			$facets->appendChild($fnode);
		}
		$this->dxml->documentElement->appendChild($facets);

		return $this->output();
	}

	/**
	 * @return XML-encoded string
	 * @since 0.5
	 */
	public function transformStatus() {
		$this->addSchema('status');
		$root = $this->dxml->createElement('dmStatus');

		// institution
		$node = $this->dxml->createElement('institution');
		$node->appendChild(
			$this->dxml->createElement('name',
				DMString::xmlentities(
						DMConfigXML::getInstance()->getInstitutionName())));
		$root->appendChild($node);

		// comments
		$node = $this->dxml->createElement('comments');
		$node->setAttribute('areAvailable',
				(int) DMConfigXML::getInstance()->isCommentingEnabled());
		$node->setAttribute('areModerated',
				(int) DMConfigXML::getInstance()->isCommentModerationEnabled());
		$root->appendChild($node);

		// tags
		$node = $this->dxml->createElement('tags');
		$node->setAttribute('areAvailable',
				(int) DMConfigXML::getInstance()->isTaggingEnabled());
		$node->setAttribute('areModerated',
				(int) DMConfigXML::getInstance()->isTagModerationEnabled());
		$root->appendChild($node);

		// ratings
		$node = $this->dxml->createElement('ratings');
		$node->setAttribute('areAvailable',
				(int) DMConfigXML::getInstance()->isRatingEnabled());
		$root->appendChild($node);

		// version
		$version = $this->dxml->createElement('version',
			DMConfigXML::getInstance()->getVersion());
		$root->appendChild($version);

		// version sequence
		$seq = $this->dxml->createElement('versionSequence',
			DMConfigXML::getInstance()->getVersionSequence());
		$root->appendChild($seq);

		$this->dxml->documentElement->appendChild($root);
		return $this->output();
	}

	/**
	 * @param DMTag tag
	 * @return XML-encoded string
	 * @since 0.4
	 */
	public function transformTag(DMTag $tag) {
		$this->addSchema('tag_view');
		$node = $this->dxml->createElement('dmTag',
			DMString::xmlentities($tag->getValue()));
		$node->setAttribute('id', $tag->getID());
		$node->setAttribute('timestamp', $tag->getTimestamp()->asISO8601());

		$obj = $this->dxml->createElement('dmObject');
		$obj->setAttribute('alias', $tag->getObject()->getCollection()->getAlias());
		$obj->setAttribute('pointer', $tag->getObject()->getPtr());
		$obj->setAttribute('xlink:type', 'simple');
		$obj->setAttribute('xlink:href',
				$tag->getObject()->getURI(DMBridgeComponent::HTTPAPI));

		$obj->appendChild($node);
		$this->dxml->documentElement->appendChild($obj);
		return $this->output();
	}

	/**
	 * @param array tags
	 * @param int page
	 * @param int rpp Results per page
	 * @param int total
	 * @return XML-encoded string
	 * @since 0.3
	 */
	public function transformTagCounts(array $tags, $page, $rpp, $total) {
		$this->addSchema("tag_counts");

		$tnode = $this->dxml->createElement("tags");
		$tnode->setAttribute("page", $page);
		$tnode->setAttribute("perPage", $rpp);
		$tnode->setAttribute("numPages", ceil($total / $rpp));
		$tnode->setAttribute("total", $total);
		foreach ($tags as $value => $count) {
			$node = $this->dxml->createElement("dmTag",
				DMString::xmlentities($value));
			$node->setAttribute("count", $count);
			$tnode->appendChild($node);
		}
		$this->dxml->documentElement->appendChild($tnode);
		return $this->output();
	}

	/**
	 * @param array freqs Associative array in value => count format
	 * @return string XML-encoded string
	 */
	public function transformVocabularyFrequencies(array $freqs) {
		$this->addSchema('vocabulary_frequency');
		$vnode = $this->dxml->createElement('vocabulary');
		foreach ($freqs as $term => $count) {
			$node = $this->dxml->createElement('term',
				DMString::xmlentities($term));
			$node->setAttribute('count', $count);
			$vnode->appendChild($node);
		}
		$this->dxml->documentElement->appendChild($vnode);
		return $this->output();
	}

	/**
	 * @param array words Indexed array of strings
	 * @return string XML-encoded string
	 */
	public function transformVocabularySuggestions(array $words) {
		$this->addSchema('vocabulary_suggestions');
		$s = $this->dxml->createElement('vocabulary');
		foreach ($words as $word) {
			$s->appendChild(
				$this->dxml->createElement('term',
						DMString::xmlentities($word)));
		}
		$this->dxml->documentElement->appendChild($s);
		return $this->output();
	}

}
